package com.naiterui.ehp.bs.im.repository.mongo;

import java.util.*;
import java.util.Map.Entry;

import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bs.im.network.protocl.*;
import com.naiterui.ehp.bs.im.utils.Constants;
import com.naiterui.ehp.bs.im.utils.DateUtils;
import com.naiterui.ehp.bs.im.vo.ImgTimeGroupVO;
import com.naiterui.ehp.bs.im.vo.PageVO;

/**
 * 负责消息数据的持久化和消息数据的获取
 * <P>File name : MessageDao.java </P>
 * <P>Author : zhouyanxin </P>
 * <P>Date : 2015年6月28日 </P>
 */
@Repository
public class MessageDao extends MongoBaseDao {

    /**
     * 消息记录的collectionName
     */
    private static final String COLLECTION_NAME_MESSAGE = "m_message";

    /**
     * 离线消息记录的collectionName
     */
    private static final String COLLECTIOIN_NAME_OFFLINE_MESSAGE = "m_offline_message";

    /**
     * 多端消息同步离线记录的collectionName
     */
    private static final String COLLECTIOIN_NAME_SYNC_OFFLINE_MESSAGE = "m_sync_offline_message";

    /**
     * 保存消息
     * MessageDao.save()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年6月28日 </P>
     *
     * @param message
     */
    public void saveMessage(Message<?> message) {
        super.save(message, COLLECTION_NAME_MESSAGE);
    }

    /**
     * 保存离线消息
     * MessageDao.saveOfflineMessage()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年7月4日 </P>
     *
     * @param message
     */
    public void saveOfflineMessage(Message<?> message) {
        super.save(message, COLLECTIOIN_NAME_OFFLINE_MESSAGE);
    }

    /*******************************************************************************
     * get and remove offline message
     ****************************************************************/

    /**
     * 获取并删除指定用户的离线消息
     * MessageDao.getAndRemoveOfflineMessages()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年7月4日 </P>
     *
     * @param toId
     *
     * @return
     */
    @SuppressWarnings("rawtypes")
    public List<Message> getAndRemoveOfflineMessages(Integer relation, Long toId) {

        Query query = Query.query(Criteria.where("to.id").is(toId).and("relation").is(relation));
        query.with(Sort.by(new Sort.Order(Direction.ASC, "sendTime")));

        return super.findAndRemove(COLLECTIOIN_NAME_OFFLINE_MESSAGE, Message.class, query);
    }

    /*******************************************************************************
     * get chat record
     *******************************************************************************/

    /**
     * 获取指定用户间聊天记录的个数
     * MessageDao.queryCountByTime()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年6月29日 </P>
     *
     * @param beginTime
     * @param fromId
     * @param toId
     *
     * @return
     */
    public long queryCount(int relation, Long beginTime, Long fromId, Long toId) {

        // 先按relation发送的，再按照 relation2查询收到的
        int relation2 = relation == 1 ? 0 : 1;

        // 日期和用户查询条件
        Criteria c1 = Criteria.where("from.id").is(fromId).and("to.id").is(toId).and("relation").is(relation);
        Criteria c2 = Criteria.where("from.id").is(toId).and("to.id").is(fromId).and("relation").is(relation2);
        Criteria c3 = new Criteria().orOperator(c1, c2);
        Criteria criteria = null;
        if (beginTime == null) {
            criteria = c3;
        } else {
            criteria = Criteria.where("sendTime").lt(beginTime).andOperator(c3);
        }

        // 查询
        Query query = Query.query(criteria);

        // 返回查询结果
        return super.queryCount(query, COLLECTION_NAME_MESSAGE);
    }

    /**
     * 查询条数
     *
     * @return
     *
     * @Author He Qiang
     * @Date 2016年1月13日
     * @since 1.0.0
     */
    public long queryCount(Long fromId, Long toId, Long beginTime, Long endTime, int relation) {

        // relation 取反
        int inverse = relation == 1 ? 0 : 1;

        // 日期和用户查询条件
        Criteria c1 = Criteria.where("sendTime").gte(beginTime);

        Criteria c2 = Criteria.where("from.id").is(fromId).and("to.id").is(toId).and("relation").is(relation);
        Criteria c3 = Criteria.where("from.id").is(toId).and("to.id").is(fromId).and("relation").is(inverse);

        Criteria criteria = c1.andOperator(new Criteria().orOperator(c2, c3));
        if (endTime != null) {
            criteria = new Criteria().andOperator(criteria, Criteria.where("sendTime").lt(endTime));
        }
        // 查询
        Query query = Query.query(criteria);

        // 返回查询结果
        return super.queryCount(query, COLLECTION_NAME_MESSAGE);
    }

    /**
     * 获取指定用户间的聊天记录
     * MessageDao.pageQueryByTime()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年6月29日 </P>
     *
     * @param beginTime
     * @param fromId
     * @param toId
     * @param page
     * @param num
     * @param orderby
     *
     * @return
     */
    @SuppressWarnings("rawtypes")
    public List<Message> pageQuery(int relation, Long beginTime, Integer visualType, Long fromId, Long toId, int page, int num, String orderby) {

        // 先按relation发送的，再按照 relation2查询收到的
        int relation2 = relation == 1 ? 0 : 1;

        // 消息可见类型
        List<Integer> visualTypeList = new ArrayList<Integer>();
        visualTypeList.add(visualType);
        visualTypeList.add(Message.MESSAGE_VISUAL_TYPE_ALL);
        Criteria visualCriteria = Criteria.where("visualType").exists(false);
        Criteria visualCriteria2 = Criteria.where("visualType").in(visualTypeList);

        // 日期和用户查询条件
        Criteria c1 = Criteria.where("from.id").is(fromId).and("to.id").is(toId).and("relation").is(relation);
        Criteria c2 = Criteria.where("from.id").is(toId).and("to.id").is(fromId).and("relation").is(relation2);
        Criteria c3 = new Criteria().orOperator(c1, c2);
        Criteria criteria = null;
        if (beginTime == null) {
            criteria = new Criteria().andOperator(c3, new Criteria().orOperator(visualCriteria, visualCriteria2));
        } else {
            criteria = Criteria.where("sendTime").lt(beginTime)
                               .andOperator(new Criteria().andOperator(c3, new Criteria().orOperator(visualCriteria, visualCriteria2)));
        }

        // 分页查询
        return this.queryByPage(COLLECTION_NAME_MESSAGE, Message.class, criteria, page, num, orderby, "sendTime");
    }

    /**
     * 根据开始时间和结束时间查询出消息列表
     *
     * @return
     *
     * @Author He Qiang
     * @Date 2016年1月13日
     * @since 1.0.0
     */
    @SuppressWarnings("rawtypes")
    public List<Message> pageQuery(Long fromId, Long toId, Long beginTime, Long endTime, int relation, int page, int num, String orderby) {
        // relation 取反
        int inverse = relation == 1 ? 0 : 1;

        // 日期和用户查询条件
        Criteria c1 = Criteria.where("sendTime").gte(beginTime);

        System.out.println(c1.toString());
        Criteria c2 = Criteria.where("from.id").is(fromId).and("to.id").is(toId).and("relation").is(relation);
        Criteria c3 = Criteria.where("from.id").is(toId).and("to.id").is(fromId).and("relation").is(inverse);

        Criteria criteria = c1.andOperator(new Criteria().orOperator(c2, c3));
        if (endTime != null) {
            criteria = new Criteria().andOperator(criteria, Criteria.where("sendTime").lt(endTime));
        }
        // 分页查询
        return super.queryByPage(COLLECTION_NAME_MESSAGE, Message.class, criteria, page, num, orderby, "sendTime");
    }

    /**
     * 获取消息集合
     * MessageDao.getMessageList()
     *
     * @param session     回话实体（session属性不可为空）
     * @param orderby
     * @param messageType
     *
     * @return
     *
     * @Date 2016年4月24日
     * @since 2.3.0
     */
    @SuppressWarnings("rawtypes")
    public List<Message> getMessageList(SessionDetails session, String orderby, Integer messageType) {

        return this.getMessageList(session.getRelation(), session.getFromId(), session.getToId(), orderby, session.getBeginTime(),
                                   session.getEndTime(),
                                   messageType);
    }

    /**
     * MessageDao.getMessageList()
     *
     * @param relation
     * @param fromId
     * @param toId
     * @param orderby
     * @param beginTime
     * @param endTime
     * @param messageType
     *
     * @return
     *
     * @Date 2016年4月24日
     * @since 2.3.0
     */
    @SuppressWarnings("rawtypes")
    public List<Message> getMessageList(int relation, Long fromId, Long toId, String orderby, Long beginTime, Long endTime, Integer messageType) {

        // 先按relation发送的，再按照 relation2查询收到的
        int relation2 = relation == 1 ? 0 : 1;

        // 日期和用户查询条件
        Criteria c1 = Criteria.where("from.id").is(fromId).and("to.id").is(toId).and("relation").is(relation);
        Criteria c2 = Criteria.where("from.id").is(toId).and("to.id").is(fromId).and("relation").is(relation2);
        Criteria c3 = new Criteria().orOperator(c1, c2);
        Criteria criteria = null;

        // 会话开始结束时间条件
        if (null != endTime) {
            criteria = Criteria.where("sendTime").gte(beginTime).lt(endTime);
        } else {
            criteria = Criteria.where("sendTime").gte(beginTime);
        }
        // 待查询消息类条件
        if (null != messageType) {
            criteria.and("type").is(messageType);
        }
        criteria.andOperator(c3);

        Query query = Query.query(criteria).with(Sort.by(new Sort.Order(Direction.DESC, orderby)));

        return this.find(query, Message.class, COLLECTION_NAME_MESSAGE);
    }

    /*******************************************************************************
     * get image upload record
     ************************************************************************/

    /**
     * 获取图片上传记录列表
     * MessageDao.getImageUploadHistory()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年6月30日 </P>
     *
     * @param patientId
     * @param doctorId
     * @param page
     * @param num
     */
    @SuppressWarnings("rawtypes")
    public PageVO<ImgTimeGroupVO> getImageUploadHistory(Long patientId, Long doctorId, Integer page, Integer num) {

        // 查询条件
        Criteria criteria = Criteria.where("from.id").is(patientId);
        if (doctorId != null) {
            criteria.and("to.id").is(doctorId);
        }
        criteria.and("type").is(Constants.MESSAGE_TYPE_MEDIA_IMG);

        // 查询条件
        Query query = Query.query(criteria).with(Sort.by(new Sort.Order(Direction.ASC, "sendTime")));

        // 返回查询结果
        List<Message> messages = super.find(query, Message.class, COLLECTION_NAME_MESSAGE);

        // 消息分组
        Map<String, List<Message>> messageGroups = new LinkedHashMap<String, List<Message>>();

        // 遍历消息进行分组
        for (Iterator<Message> iter = messages.iterator(); iter.hasNext(); ) {

            // 消息对象
            Message message = iter.next();

            // 发送的日期 格式YYYY-MM-DD
            String sendTimeDate = DateUtils.formatDate(message.getSendTime(), DateUtils.DATE_FORMAT2);

            // 获取分组集合
            List<Message> messageBeanList = messageGroups.get(sendTimeDate);

            // 初始化分组集合
            if (messageBeanList == null) {
                messageBeanList = new ArrayList<Message>();
                messageGroups.put(sendTimeDate, messageBeanList);
            }

            messageBeanList.add(message);
        }

        // 总记录数
        int totalCount = messageGroups.keySet().size();

        // 总页数
        int totalPage = totalCount / num;
        if (totalCount % num > 0) {
            totalPage++;
        }

        // 限制page不能超出最大页
        /*
         * if(page > totalPage) {
         * page = totalPage;
         * }
         */

        // 计算分页的起始位置和偏移量
        int start = (page - 1) * num;
        int end = page * num - 1;
        if (end > totalCount - 1) {
            end = totalCount - 1;
        }

        // 分组记录集合
        List<ImgTimeGroupVO> imgTimeGroups = new ArrayList<ImgTimeGroupVO>();

        // 记录偏移量
        int offset = 0;

        // 获取分页记录
        for (Iterator<Entry<String, List<Message>>> iter = messageGroups.entrySet().iterator(); iter.hasNext(); ) {

            // entry
            Entry<String, List<Message>> entry = iter.next();

            // 分页内的数据记录
            if (offset >= start && offset <= end) {
                ImgTimeGroupVO vo = new ImgTimeGroupVO();
                vo.setDate(entry.getKey());
                vo.setImages(this.getImageUrls(entry.getValue()));
                imgTimeGroups.add(vo);
            }

            // 偏移量++
            offset++;
        }

        // 返回值
        PageVO<ImgTimeGroupVO> pageVO = new PageVO<ImgTimeGroupVO>();
        pageVO.setPageNo(page);
        pageVO.setPageSize(num);
        pageVO.setResult(imgTimeGroups);
        pageVO.setTotalCount(totalCount);
        pageVO.setTotalPage(totalPage);

        return pageVO;
    }

    /*******************************************************************************
     * private methods
     *******************************************************************************/

    /**
     * 获取图片的url集合
     * MessageDao.getImageUrls()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年6月30日 </P>
     *
     * @param messages
     *
     * @return
     */
    @SuppressWarnings("rawtypes")
    private List<String> getImageUrls(List<Message> messages) {
        List<String> imageUrls = new ArrayList<String>();
        for (Iterator<Message> iter = messages.iterator(); iter.hasNext(); ) {
            Message message = iter.next();
            imageUrls.add(((Media) message.getContent()).getPath());
        }
        return imageUrls;
    }

    /**
     * 跨会话历史消息查(最后发送时间向上回溯)
     * MessageDao.pageQueryCross()
     *
     * @param fromId
     * @param toId
     * @param endTime
     * @param relation
     * @param page
     * @param num
     * @param orderby
     *
     * @return
     *
     * @Date 2016年6月17日
     * @since 2.5.0
     */
    @SuppressWarnings("rawtypes")
    public List<Message> pageQueryCross(Long fromId, Long toId, int relation, Long endTime, Integer visualType, int page, int num, String orderby) {
        // relation 取反
        int inverse = relation == 1 ? 0 : 1;

        // 最后捞取时间向上回溯
        // 消息可见类型
        List<Integer> visualTypeList = new ArrayList<Integer>();
        visualTypeList.add(visualType);
        visualTypeList.add(Message.MESSAGE_VISUAL_TYPE_ALL);
        Criteria visualCriteria = Criteria.where("visualType").exists(false);
        Criteria visualCriteria2 = Criteria.where("visualType").in(visualTypeList);

        Criteria c1 = Criteria.where("sendTime").lt(endTime);
        Criteria c2 = Criteria.where("from.id").is(fromId).and("to.id").is(toId).and("relation").is(relation);
        Criteria c3 = Criteria.where("from.id").is(toId).and("to.id").is(fromId).and("relation").is(inverse);

        Criteria criteria = c1.andOperator(new Criteria().orOperator(c2, c3), new Criteria().orOperator(visualCriteria, visualCriteria2));

        // 分页查询
        return super.queryByPage(COLLECTION_NAME_MESSAGE, Message.class, criteria, page, num, orderby, "sendTime");
    }

    /**
     * 查询session中最后一条消息
     *
     * @param fromId
     * @param toId
     * @param endTime
     * @param relation
     *
     * @return
     *
     * @Author He Qiang
     * @Date 2016年1月19日
     * @since 1.0.0
     */
    @SuppressWarnings("rawtypes")
    public Message<?> findLastRecord(Long fromId, Long toId, Long endTime, int relation) {

        int reverse = relation == 1 ? 0 : 1;

        Criteria c1 = Criteria.where("sendTime").lte(endTime);
        Criteria c2 = Criteria.where("fromId").is(fromId).and("toId").is(toId).and("relation").is(relation);
        Criteria c3 = Criteria.where("toId").is(fromId).and("fromId").is(toId).and("relation").is(reverse);

        Criteria criteria = c1.andOperator(new Criteria().orOperator(c2, c3));

        Query query = Query.query(criteria);
        query.with(Sort.by(Direction.DESC, "sendTime"));

        Message message = super.findOne(query, Message.class, COLLECTION_NAME_MESSAGE);
        return message;
    }

    /**
     * MessageDao.findLastRecord()
     *
     * @param fromId
     * @param toId
     * @param endTime
     * @param msgType
     * @param relation
     *
     * @return
     *
     * @Author Gaoll
     * @Date 2016年8月16日
     * @since 1.0.0
     */
    @SuppressWarnings("rawtypes")
    public Message<?> findLastRecord(Long fromId, Long toId, Long beginTime, Long endTime, int msgType, int relation) {

        int reverse = relation == 1 ? 0 : 1;

        Criteria c0 = new Criteria();
        if (msgType > 0) {
            c0 = Criteria.where("type").is(msgType);
        }

        Criteria c1 = new Criteria();
        if (null != beginTime && beginTime.longValue() > 0 && null != endTime && endTime.longValue() > 0) {
            c1 = Criteria.where("sendTime").gte(beginTime).lte(endTime);
        } else if ((null == beginTime || beginTime.longValue() == 0) && (null == endTime || endTime.longValue() == 0)) {
            c1 = new Criteria();
        } else if (null != endTime && endTime.longValue() > 0) {
            c1 = Criteria.where("sendTime").lte(endTime);
        } else if (null != beginTime && beginTime.longValue() > 0) {
            c1 = Criteria.where("sendTime").gte(beginTime);
        }

        Criteria c2 = Criteria.where("fromId").is(fromId).and("toId").is(toId).and("relation").is(relation);
        Criteria c3 = Criteria.where("toId").is(fromId).and("fromId").is(toId).and("relation").is(reverse);

        Criteria criteria = new Criteria().andOperator(c0, c1, new Criteria().orOperator(c2, c3));

        Query query = Query.query(criteria);
        query.with(Sort.by(Direction.DESC, "sendTime"));

        Message message = super.findOne(query, Message.class, COLLECTION_NAME_MESSAGE);
        return message;

    }

    /**
     * 根据recommandId查询对应的消息,单纯处方、病历-处方
     *
     * @param recommandId
     *
     * @return
     *
     * @Author He Qiang
     * @Date 2016年7月21日
     * @since 1.0.0
     */
    public Message<?> findAndModifyByDrug(long recommandId, int status, String suggest, long sendTime, int visualType, int sysMsgType) {
        Query query = Query.query(Criteria.where("content.recommandId").is(recommandId)
                                          .andOperator(Criteria.where("type")
                                                               .in(Constants.MESSAGE_TYPE_DRUG, Constants.MESSAGE_TYPE_DOCTORS_MEDICALRECORD)));
        Update update = new Update();
        update.set("sendTime", sendTime);

        update.set("content.auditDesc", suggest);
        update.set("visualType", visualType);
        // 设置系统消息标识
        update.set("sysMsgType", sysMsgType);
        Message<?> message = super.findOne(query, Message.class, COLLECTION_NAME_MESSAGE);
        if (message.getType() == Constants.MESSAGE_TYPE_DRUG) {
            update.set("content.recommandStatus", status);
        }
        if (message.getType() == Constants.MESSAGE_TYPE_DOCTORS_MEDICALRECORD) {
            update.set("content.checkingStatus", status);
        }
        super.findAndModify(query, update, Message.class, COLLECTION_NAME_MESSAGE);
        return message;
    }

    /**
     * 根据recommandId查询对应的消息,处方作废
     *
     * @param recommandId
     *
     * @return
     *
     * @Author lijiafu
     * @Date 2018年10月17日
     * @since 3.4.0
     */
    public void findAndModifyByInvalidDrug(long recommandId) {
        Query query = Query.query(Criteria.where("content.recommandId").is(recommandId)
                                          .andOperator(Criteria.where("type")
                                                               .in(Constants.MESSAGE_TYPE_DRUG, Constants.MESSAGE_TYPE_DOCTORS_MEDICALRECORD)));
        Message<?> message = super.findOne(query, Message.class, COLLECTION_NAME_MESSAGE);
        // 根据消息类型，匹配处方作废标识
        Update update = this.getInvalidParameter(message);
        if (null == update) {
            return;
        }
        super.findAndModify(query, update, Message.class, COLLECTION_NAME_MESSAGE);
    }

    // 根据消息类型，匹配处方作废标识
    private Update getInvalidParameter(Message<?> message) {
        Update update = new Update();
        // 无效标识(0 正常 1 处方作废、2 病历作废、3 处方和病历作废)
        Integer invalid = RecommandDrug.RECOMMAND_DRUG_VALID;
        // 药方消息
        if (message.getType() == Constants.MESSAGE_TYPE_DRUG) {
            RecommandDrug recommandDrug = (RecommandDrug) message.getContent();
            if (null != recommandDrug.getInvalid()) {
                invalid = recommandDrug.getInvalid();
            }
            if (recommandDrug.getRecommandStatus() != RecommandDrug.RECOMMAND_TYPE_NO_CHECK) {
                //作废的推荐消息用药状态更改为0： 不需要审核
                update.set("content.recommandStatus", RecommandDrug.RECOMMAND_TYPE_NO_CHECK);
            }
        }
        // 病历药方消息
        if (message.getType() == Constants.MESSAGE_TYPE_DOCTORS_MEDICALRECORD) {
            DoctorsMedicalRecord doctorsMedicalRecord = (DoctorsMedicalRecord) message.getContent();
            if (null != doctorsMedicalRecord.getInvalid()) {
                invalid = doctorsMedicalRecord.getInvalid();
            }
            if (doctorsMedicalRecord.getCheckingStatus() != RecommandDrug.RECOMMAND_TYPE_NO_CHECK) {
                //作废的推荐消息用药状态更改为0： 不需要审核
                update.set("content.checkingStatus", RecommandDrug.RECOMMAND_TYPE_NO_CHECK);
            }
        }
        switch (invalid) {
            case RecommandDrug.RECOMMAND_DRUG_VALID:
                // 标识为处方作废
                update.set("content.invalid", RecommandDrug.RECOMMAND_DRUG_INVALID);
                break;
            case RecommandDrug.RECOMMAND_DRUG_INVALID:
                return null;
            case RecommandDrug.RECOMMAND_MEDICAL_RECORD_INVALID:
                // 标识为处方和病历作废
                update.set("content.invalid", RecommandDrug.RECOMMAND_DRUG_AND_RECORD_INVALID);
                break;
            case RecommandDrug.RECOMMAND_DRUG_AND_RECORD_INVALID:
                return null;
            default:
                return null;
        }
        return update;
    }

    /**
     * 根据病历Id查询对应的消息, 病历作废
     *
     * @param medicalRecordId
     *
     * @return
     *
     * @Author lijiafu
     * @Date 2018年10月17日
     * @since 3.4.0
     */
    public void findAndModifyByInvalidRecord(String medicalRecordId) {
        Query query = Query.query(Criteria.where("content.medicalRecordId").is(medicalRecordId)
                                          .andOperator(Criteria.where("type").is(Constants.MESSAGE_TYPE_DOCTORS_MEDICALRECORD)));
        Message<?> message = super.findOne(query, Message.class, COLLECTION_NAME_MESSAGE);
        Update update = new Update();
        DoctorsMedicalRecord doctorsMedicalRecord = (DoctorsMedicalRecord) message.getContent();
        if (doctorsMedicalRecord.getCheckingStatus() != RecommandDrug.RECOMMAND_TYPE_NO_CHECK) {
            //作废的推荐消息用药状态更改为0： 不需要审核
            update.set("content.checkingStatus", RecommandDrug.RECOMMAND_TYPE_NO_CHECK);
        }
        // 无效标识(0 正常 1 处方作废、2 病历作废、3 处方和病历作废)
        Integer invalid = doctorsMedicalRecord.getInvalid();
        if (null == invalid) {
            invalid = RecommandDrug.RECOMMAND_DRUG_VALID;
        }
        switch (invalid) {
            case RecommandDrug.RECOMMAND_DRUG_VALID:
                // 标识为处方作废
                update.set("content.invalid", RecommandDrug.RECOMMAND_MEDICAL_RECORD_INVALID);
                break;
            case RecommandDrug.RECOMMAND_DRUG_INVALID:
                // 标识为处方和病历作废
                update.set("content.invalid", RecommandDrug.RECOMMAND_DRUG_AND_RECORD_INVALID);
                break;
            default:
                return;
        }
        super.findAndModify(query, update, Message.class, COLLECTION_NAME_MESSAGE);
    }

    /**
     * MessageDao.getAndRemoveSyncOfflineMessages()
     *
     * @param messageResourcePatient
     * @param userId
     *
     * @return
     *
     * @Author Gaoll
     * @Date 2016年8月11日
     * @since HZD-1.0.0
     */
    @SuppressWarnings("rawtypes")
    public List<Message> getAndRemoveSyncOfflineMessages(int relation, Long userId) {

        Query query = Query.query(Criteria.where("from.id").is(userId).and("relation").is(relation));
        query.with(Sort.by(new Sort.Order(Direction.ASC, "sendTime")));

        return super.findAndRemove(COLLECTIOIN_NAME_SYNC_OFFLINE_MESSAGE, Message.class, query);
    }

    /**
     * MessageDao.saveSyncOfflineMessage()
     *
     * @param message
     *
     * @Author Gaoll
     * @Date 2016年8月11日
     * @since HZD-1.0.0
     */
    public void saveSyncOfflineMessage(Message<?> message) {
        super.save(message, COLLECTIOIN_NAME_SYNC_OFFLINE_MESSAGE);
    }

    @SuppressWarnings("rawtypes")
    public Message getMessageBySendTime(Long fromId, Long toId, int relation, Long sendTime) {
        Query query = Query
                .query(Criteria.where("from.id").is(fromId).and("to.id").is(toId).and("relation").is(relation).and("sendTime").is(sendTime));
        query.with(Sort.by(new Sort.Order(Direction.ASC, "sendTime")));

        return super.findOne(query, Message.class, COLLECTION_NAME_MESSAGE);
    }

    public long queryCountByMsgType(int relation, Long fromId, Long toId, Long beginTime, Long endTime, Integer messageType) {
        // 先按relation发送的，再按照 relation2查询收到的
        int relation2 = relation == 1 ? 0 : 1;

        // 日期和用户查询条件
        Criteria c1 = Criteria.where("from.id").is(fromId).and("to.id").is(toId).and("relation").is(relation);
        Criteria c2 = Criteria.where("from.id").is(toId).and("to.id").is(fromId).and("relation").is(relation2);
        Criteria c3 = new Criteria().orOperator(c1, c2);
        Criteria criteria = null;

        // 会话开始结束时间条件
        if (null != endTime) {
            criteria = Criteria.where("sendTime").gte(beginTime).lt(endTime);
        } else {
            criteria = Criteria.where("sendTime").gte(beginTime);
        }
        // 待查询消息类条件
        if (null != messageType) {
            criteria.and("type").is(messageType);
        }
        criteria.andOperator(c3);

        Query query = Query.query(criteria);

        return this.queryCount(query, COLLECTION_NAME_MESSAGE);
    }

    /**
     * MessageDao.queryCountByCondition()
     *
     * @param relation
     * @param fromId
     * @param toId
     * @param beginTime
     * @param messageType
     *
     * @return
     *
     * @Author mudou
     * @Date 2016年12月7日
     * @since 2.6.5
     */
    public long queryCountByCondition(int relation, Long fromId, Long toId, Long beginTime, Integer messageType) {

        // 日期和用户查询条件
        Criteria c1 = Criteria.where("from.id").is(fromId).and("relation").is(relation);
        if (null != toId) {
            c1.and("to.id").is(toId);
        }

        Criteria criteria = null;
        // 会话开始结束时间条件
        if (null != beginTime) {
            criteria = Criteria.where("sendTime").gte(beginTime);
        } else {
            criteria = Criteria.where("sendTime").gte(DateUtil.convertDate(new Date()).getTime());
        }
        // 待查询消息类条件
        if (null != messageType) {
            criteria.and("type").is(messageType);
        }
        criteria.andOperator(c1);

        Query query = Query.query(criteria);

        return this.queryCount(query, COLLECTION_NAME_MESSAGE);
    }

    public long queryCountByCondition(int relation, Long fromId, Long toId) {

        return this.queryCountByCondition(relation, fromId, toId, null, null);
    }

    public void updateMessage(String id) {
        Query query = Query.query(Criteria.where("id").is(id));
        Update update = new Update();
        update.set("content.read", 1);

        super.findAndModify(query, update, Message.class, COLLECTION_NAME_MESSAGE);
        // super.remove(query, COLLECTION_NAME_MESSAGE);
    }

    /**
     * 查询会话消息是否包含用户主动回复类型消息
     * MessageDao.queryConsumerMessageCount()
     *
     * @param relation
     * @param fromId
     * @param toId
     * @param beginTime
     * @param endTime
     *
     * @return
     *
     * @Author guoyongxiang
     * @Date 2017年6月14日
     * @since 2.8.0
     */
    public long queryConsumerMessageCount(int relation, Long fromId, Long toId, Long beginTime, Long endTime) {
        Criteria criteria = Criteria.where("from.id").is(fromId).and("relation").is(relation);
        criteria.and("to.id").is(toId);
        criteria.and("sendTime").gte(beginTime).lte(endTime);
        criteria.and("sysMsgType").is(Message.SYS_MSG_TYPE_CONSUMER);
        Query query = Query.query(criteria);
        return this.queryCount(query, COLLECTION_NAME_MESSAGE);
    }

    /**
     * 根据recommandId查询对应的推荐消息
     *
     * @param recommandId
     *
     * @return
     *
     * @Author dongqing
     * @since 2.14
     */
    public Message findDrugByRecommandId(long recommandId) {
        Query query = Query.query(Criteria.where("content.recommandId").is(recommandId)
            .andOperator(Criteria.where("type").in(Constants.MESSAGE_TYPE_DRUG)));
        Message<RecommandDrug> message = super.findOne(query, Message.class, COLLECTION_NAME_MESSAGE);
        return message;
    }

    /**
     * 修改消息可见级别
     * 
     * @param id
     * @param visualType
     */
    public void updateVisualType(String id, Integer visualType) {
        Query query = Query.query(Criteria.where("id").is(id));
        Update update = new Update();
        update.set("visualType", visualType);

        super.findAndModify(query, update, Message.class, COLLECTION_NAME_MESSAGE);
    }
}
